<template>
  <div class="base-select-container">
    <div class="content el-select el-input el-input--small el-input--suffix" v-clickoutside="closeList" ref="BaseSelectContainer">
      <!-- start 多选显示 -->
      <div 
        v-if="multiple"
        class="base-select-main-content multiple-layout el-input el-input__inner" 
        ref="normalInput"
        :class="{'error': error, 'wrapper-is-focus': isFocus, 'clearable-layout': clearable}"
        @click.stop="focusInput" 
      >
        
        <!-- start 显示标签 -->
        <el-tag size="mini" :closable="!disabled" v-for="tag in (collapsed ? value[0] ? [value[0]] : [] : value)" :key="getValueKey(tag)" @close="removeTag(tag)" disable-transitions type="info">
          <template v-if="isOpenData && tag.staffId">
            <open-data type="userName" :openid="tag.staffId"></open-data>
          </template>
          <template v-else-if="isOpenData && isUseValue">
            <open-data type="userName" :openid="tag.value"></open-data>
          </template>
          <template v-else>
            {{tag.label ||tag.name|| tag[valueKey]}}
          </template>
        </el-tag>
        <!-- end 显示标签 -->
        
        <!-- start 显示折叠的标签 -->
        <div v-if="collapsed && value.length > 1" class='base-user-select-tag'>
          + {{value.length - 1}}
        </div>
        <!-- end 显示折叠的标签 -->
        
        <!-- start 显示占位符 -->
        <span v-if="value.length <= 0" class="placeholder-text">
          {{ placeholder }}
        </span>
        <!-- end 显示占位符 -->
        
        <!-- start 图标 -->
        <span
          class="el-input__suffix"
          :class="{
            'has-clear': clearable && value.length
          }">
          <span class="el-input__suffix-inner">
            <i class="el-select__caret el-input__icon el-icon-arrow-up" :class="showList && 'is-reverse'"></i>
          </span>
        </span>
        <!-- end 图标 -->
        
      </div>
      <!-- end 多选显示 -->
      
      <!-- start 单选显示 -->
      <div 
        v-else
        class="base-select-main-content" 
        :class="{'error': error, 'wrapper-is-focus': isFocus, 'clearable-layout': clearable,}"
        ref="normalInput"
        @click.stop="focusInput" 
      >
        
        <!-- start 插槽： 标签 -->
        <slot name="label" :value="value" v-if="labelSlot"></slot>
        <!-- end 插槽： 标签 -->
        
        <!-- start 默认显示标签 -->
        <template v-else>
          <template v-if="value && value.length">
            <template v-if="isOpenData">
              <template v-for="item in value">
                <open-data v-if="item.staffId" :key="item.staffId" type="userName" :openid="item.staffId"></open-data>
                <template v-else>
                  {{ item.label || item.name || item[valueKey]  }}
                </template>
              </template>
            </template>
            <template v-else>
              <template v-if="isTaskCardMultiple && value.length > 1">
                <el-tag size="mini" :closable="!disabled" v-for="tag in (collapsed ? value[0] ? [value[0]] : [] : value)" :key="getValueKey(tag)" @close="removeTag(tag)" disable-transitions type="info">
                  {{tag.label || tag.name|| tag[valueKey]}}
                </el-tag>
              </template>
              <template v-else> {{ value.map(tag => tag.label || tag.name || tag[valueKey]).join('') }} </template>
            </template>
          </template>
        </template>
        <!-- end 默认显示标签 -->

        <!-- start 显示占位符 -->
        <span v-if="value.length <= 0" class="placeholder-text">
          {{ placeholder }}
        </span>
        <!-- end 显示占位符 -->

      </div>
      <!-- start 单选显示 -->

      <!-- start 清除按钮 -->
      <i v-if="clearable && value.length" class="iconfont icon-circle-delete clear-btn" @click="clearValue"></i>
      <!-- end 清除按钮 -->

      <!-- start 列表 -->
      <transition name="el-zoom-in-top">
        <div 
          v-if="showList"
          class="list-wrapper" 
          ref="popper"
          :class="{ 'is-multiple': multiple, inputAlwayTop }"
          :style="popperStyle"
          @click.stop
        >
          <div class="arrow" data-popper-arrow></div>
          <template v-if="!topShow">
            <div class="input-container" v-if="!options.length">
              <div class="mar-r-8" @mousedown="stopMouseDownHandler($event)" v-if="selectMode">
                <el-select 
                  :style="{ 'width': selectWidth + 'px' }" 
                  :popper-append-to-body="false" 
                  v-model="selectValue" 
                  slot="prepend" 
                  @change="selectChange"
                >
                  <el-option v-for="(item, index) in  selectOptions" :label="item.label" :value="item.value"></el-option>
                </el-select>
              </div>
              <input 
                type="text" 
                ref="input" 
                v-model="keyword" 
                :placeholder="placeholder"
                :autoComplete="autoComplete"
                @mousedown="($event)=>{ $event.stopPropagation() }"
                @input="searchByKeyword" 
              >
            </div>
          </template>
          <ul
            class="option-list"
            v-loadmore="loadmoreOptions"
            ref="list"
            @mousedown="stopMouseDownHandler($event)"
            v-if="showList" >
            <li
              v-for="(op) in optionList"
              :key="op.value" 
              @click.stop="selectTag(op, $event)"
              @mousedown="stopMouseDownHandler($event)"
              :class="{'selected': value.some(user => user[valueKey] ===op[valueKey])}"
            >
              <slot name="option" :option="op" v-if="optionSlot"></slot>
              <template v-else>{{op.label}}</template>
              <div class="checked"></div>
            </li>
            
            <li class="list-message" style="text-align: center;" v-if="message">{{message}}</li>
          </ul>
          <template v-if="topShow">
            <div v-if="!options.length" class="input-container">
              <div class="mar-r-8" @mousedown="stopMouseDownHandler($event)" v-if="selectMode">
                <el-select 
                  :style="{ 'width': selectWidth + 'px' }" 
                  :popper-append-to-body="false" 
                  v-model="selectValue" 
                  slot="prepend" 
                  @change="selectChange"
                >
                  <el-option v-for="(item, index) in  selectOptions" :label="item.label" :value="item.value"></el-option>
                </el-select>
              </div>
              <input
                id="stopEvent"
                type="text" 
                v-model="keyword" 
                @input="searchByKeyword" 
                :autoComplete="autoComplete"
                @mousedown="($event)=>{ $event.stopPropagation() }"
                ref="input" 
                :placeholder="placeholder"
              >
            </div>
            
          </template>
        </div>
      </transition>
      <!-- end 列表 -->
      
    </div>
  </div>
</template>

<script>
import { t } from '@src/locales'
import { isOpenData } from '@src/util/platform';
/* util */
import _ from 'lodash';
import Clickoutside from '@src/util/clickoutside';
import { createPopper } from '@popperjs/core';
/* model */
import Page from '@model/Page';
/* variable */
let timeInterval;
/**
   * Todo
   * 1. 列表出现在上部还是下部。
   * 2. 点击空白隐藏列表。✅
   * 3. 配置 key value 的name，还是整理好列表传进来
   * 4. 关闭弹窗没有重置联系人 ✅
   * 5. 配置多选单选
   * 6. 配置可一键清空
   * 7. 配置是否远程搜索
   * 8. option的自定义
   * 9. 布局调整，搜索框和列表在一起
   * 10.
   */
export default {
  name: 'base-select',
  props: {
    remoteMethod: Function,
    value: {
      type: Array,
      default: () => ([]),
    },
    valueKey: {
      type: String,
      default: 'value'
    },
    error: {
      type: Boolean,
      default: false,
    },
    multiple: {
      type: Boolean,
      default: false,
    },
    clearable: {
      type: Boolean,
    },
    options: {
      type: Array,
      default: () => ([]),
    },
    placeholder: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    },
    collapsed: {
      type: Boolean,
      default: false
    },
    /** 
     * popper options
     * @see https://github.com/FezVrasta/popper.js/blob/master/docs/_includes/popper-documentation.md
     */
    popperOptions: {
      type: Object,
      default: () => ({})
    },
    /* 计算宽度的属性 */
    computedWidthKeys: {
      type: Array,
      default: () => []
    },
    isUseValue: {
      type: Boolean,
      default: false
    },
    inputAlwayTop: {
      type: Boolean,
      default: false
    },
    messageProp:{
      type: Object,
      default: (()=>{
        return {
          pending: t('common.base.loading'),
          nothing: t('common.base.tip.noRes'),
          finish: t('common.base.finishLoadData'),            
        }
      })
    },
    autoComplete: {
      type: String,
      default: 'on'
    },
    isDisabledSelectPanel: {
      type: Boolean,
      default: false
    },
    apppendToBody: {
      type: Boolean,
      default: true,
    },
    // 是否是关联工单附加组件单选并且开启显示字段
    isTaskCardMultiple: {
      type: Boolean,
      default: false,
    },
    selectWidth: {
      type: Number,
      default: 100
    },
    selectOptions: {
      type: Array,
      default: () => []
    },
    selectMode: {
      type: Boolean,
      default: false
    },
  },
  data() {
    return {
      isOpenData,
      $parentEl: document.body,
      popperInstance: null, // popper 实例
      popperWidth: 0,
      showList: false,
      pending: false,
      isFocus: false,
      keyword: '',
      loadmoreOptions: {
        disabled: false,
        callback: this.loadmore,
        distance: 10,
      },
      page: new Page(),
      selectCon: null,
      topShow: false,
      selectValue: '',
    }
  },
  watch: {
    showList(newV, oldV) {
      if (newV == true) {
        timeInterval = setInterval(() => {
          let res_ = this.$refs['normalInput'].getBoundingClientRect()
          let bottomH = window.innerHeight
              - res_.y
              - res_.height;
          if (bottomH < 370) {
            this.topShow = true;
          }else{
            this.topShow = false;
          }
          this.selectCon = res_;
        }, 100)
      } else {
        clearInterval(timeInterval)
      }
    }
  },
  beforeDestroy() {
    clearInterval(timeInterval)
    // 销毁popper
    this.popperInstance?.destroy()
  },
  computed: {
    optionList() {
      if (this.options.length) return this.options;
      return this.page.list;
    },
    optionSlot() {
      return !!this.$scopedSlots.option;
    },
    labelSlot() {
      return !!this.$scopedSlots.label;
    },
    message() {
      const {
        total,
        hasNextPage,
      } = this.page;
      if (this.pending) {
        return this.messageProp?.pending ?? t('common.base.loading');
      }
      if (!total) {
        return this.messageProp?.nothing ?? t('common.base.tip.noRes');
      }
      if (!hasNextPage) {
        return this.messageProp?.finish ?? t('common.base.finishLoadData');
      }
      return this.messageProp?.pending ?? t('common.base.loading');
    },
    // 最小宽度
    minWidth() {
      return `${this.$el?.getBoundingClientRect()?.width}px`
    },
    popperStyle() {
      this.popperWidth = this.$el.offsetWidth;
      if(this.popperWidth > 465) {
        return {
          width: `${this.popperWidth}px`,
          minWidth: this.minWidth
        } 
      } else {
        return {
          maxWidth: '465px',
          width: `${this.popperWidth}px`,
        }
      }
    }
  },
  methods: {
    getValueKey(op) {
      return `${op[this.valueKey]}`;
    },
    focusInput() {
      if (this.disabled) return
      if (this.showList) return this.close()
      this.isFocus = true
      this.$emit('focus')
      
      if (!this.isDisabledSelectPanel) {
        this.initList()
      }
      
    },
    closeList(e) {
      this.showList = false;
      this.isFocus = false;
      this.pending = true;
      this.resetStatus('');
    },
    clearValue() {
      this.$emit('input', []);
    },
    removeTag(tag) {
      const newVal = this.value.filter(t => t[this.valueKey] !== tag[this.valueKey]);
      this.$emit('input', newVal);
    },
    stopMouseDownHandler(event) {
      event.stopPropagation()
      event.preventDefault()
    },
    selectTag(tag, event) {
      let newValue = this.value;
      
      if (!this.multiple) {
        newValue = [tag];
        this.showList = false;
        this.resetStatus();
        
      } else {
        if (this.value.every(t => t[this.valueKey] !== tag[this.valueKey])) {
          newValue.push(tag);
        } else {
          newValue = newValue.filter(t => t[this.valueKey] !== tag[this.valueKey]);
        }
      }
      
      this.$emit('input', newValue);
      
      this.$nextTick(() => {
        this.popperInstance.update()
      })
    },
    async loadmore() {
      this.loadmoreOptions.disabled = true;
      this.loading = true;
      
      try {
        this.page.pageNum += 1;
        const res = await this.search();
        this.page.merge(res);
      } catch (e) {
        console.error('e', e);
      }
    },
    search() {
      if (!this.remoteMethod) return;
      const {
        pageNum,
        pageSize,
      } = this.page;
      const params = {
        keyword: this.keyword,
        pageNum,
        pageSize,
      }
      if(this.selectMode) {
        params.selectValue = this.selectValue
      }
      return this.remoteMethod(params)
        .then(res => {
          this.pending = false;
          this.loadmoreOptions.disabled = res ? !res.hasNextPage : false;
          return res;
        })
        .catch(err => console.error(err))
    },
    searchByKeyword: _.debounce(function (e) {
      this.resetStatus(e.target.value);
      this.pending = true;
      this.search()
        .then(res => {
          if (!res || !res.list) return;
          this.$refs.list.scrollTop = 0;
          this.page = Page.as(res);
        })
        .catch(e => {
          console.error('searchByKeyword catch e', e)
        });
    }, 800),
    initList() {
      this.pending = true;
      this.showList = true
      try {
        if(this.selectMode) {
          // 默认第一个选项
          this.selectValue = this.selectOptions[0].value
        }
      } catch(error) {
        console.error('initList catch error', error)
      }
      
      this.$nextTick(() => {
        this.createPopper()
      })
      
      this.search()
        .then(res => {
          if (!res || !res.list) return
          
          this.page = Page.as(res)
          this.$refs.input.focus()
        })
        .catch(e => {
          console.error('initList catch e', e)
        });
    },
    resetStatus(keyword) {
      this.keyword = keyword || '';
      this.page = new Page();
    },
    close() {
      this.showList = false;
    },
    createPopper() {
      let options = {
        placement: 'bottom-start',
        modifiers: [
          {
            name: 'offset',
            options: {
              offset: [0, 8],
            },
          },
          {
            name: 'flip',
            options: {
              fallbackPlacements: ['top-start'],
              // boundary: element,
            },
          },
        ],
      }
      this.apppendToBody && document.body.appendChild(this.$refs.popper)
      this.popperInstance = createPopper(this.$refs.BaseSelectContainer, this.$refs.popper, {...options, ...this.popperOptions})
    },
    selectChange() {
      this.searchByKeyword({target: {value: this.keyword}})
    }
  },
  directives: {
    Clickoutside
  }
}
</script>

<style lang="scss">
  
  .form-item.err :not(.is-success) input,
  .form-item.err :not(.is-success) .base-select-main-content {
    border-color: #f56c6c !important;
  }
  
  .base-select-container {
    position: relative;
    
    .content {
      position: relative;
      
      &:hover {
        .clear-btn {
          display: block;
        }
        .el-input__suffix.has-clear {
          display: none;
        }
      }

      .el-input__suffix {
        height: calc(100% + 2px);
        top: -2px;
      }

      
      .clear-btn {
        position: absolute;
        display: none;
        top: 50%;
        right: 12px;
        transform: translateY(-50%);
        font-size: 12px;
        color: #8C8C8C;
        
        &:hover {
          cursor: pointer;
          // color: #f56c6c;
        }
      }
    }
    
    .base-select-main-content {
      
      display: flex;
      flex-wrap: wrap;
      border: 1px solid #e0e1e2;
      border-radius: 4px;
      padding: 0 24px 0 10px;
      min-height: 32px;
      max-height: 62px;
      line-height: 30px;
      word-break: break-all;
      overflow: auto;
      
      .placeholder-text {
        color: #b3b7c1;
        font-size: 13px;
        line-height: 20px;
        margin-top: 5px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }
      
      .el-tag {
        margin: 5px 3px 0px;
      }
    }
    
    .wrapper-is-focus {
      border-color: $color-primary;
    }
    
    .multiple-layout {
      padding-bottom: 5px;
      position: static;
    }
    
    .clearable-layout {
      padding-right: 20px;
    }
    
    .error.base-select-main-content {
      border-color: red;
    }
  }

  .base-user-select-tag {
    background-color: #f0f2f5;
    height: 22px;
    margin: 3px;
    padding: 0 5px;
    color: #909399;
    border-radius: 4px;
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
  }
</style>

<style lang="scss">
  .base-select-container {
    .el-select {
      width: 100%;
    }

    .el-select .el-input .el-select__caret.is-reverse {
      transform: rotateZ(0deg);
    }
  }

  
.base-select-main-content {
  &:hover {
    border-color: $color-primary;
    cursor: pointer;
  }
  height: 100% !important;
}

.list-wrapper {
  border-radius: 4px;
  position: fixed;
  left: 0;
  top: calc(100% + 13px);
  width: 100%;
  height: 240px;
  // padding-top: 34px;
  box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.15);
  background: #fff;
  z-index: 99999;
  
  // .arrow {
  //   position: absolute;
  //   width: 0;
  //   height: 0;
  //   top: -7px;
  //   left: 37px;
  //   border-left: 5px solid transparent;
  //   border-right: 5px solid transparent;
  //   border-bottom: 7px solid white;
  // }

  .arrow,
  .arrow::before {
    position: absolute;
    width: 8px;
    height: 8px;
    background: white;
  }

  .arrow {
    visibility: hidden;
  }

  .arrow::before {
    visibility: visible;
    content: '';
    transform: rotate(45deg);
  }

  &[data-popper-placement^='top-start'] > .arrow {
    bottom: -4px;
  }

  &[data-popper-placement^='bottom-start'] > .arrow {
    top: -4px;
  }
  
  .input-container {
    // position: absolute;
    width: 100%;
    // top: 0;
    // left: 0;
    padding: 4px 10px;
    line-height: 34px;
    display: flex;
    align-items: center;
    input {
      width: 100%;
      margin: 2px 0;
      padding: 0 5px;
      height: 26px;
      line-height: 26px;
    }
  }
    
  .option-list {
    height: 200px;
    width: 100%;
    overflow: auto;
    padding: 0;
    margin: 0;
    
    &::-webkit-scrollbar-track {
      background-color: white;
    }
    
    &::-webkit-scrollbar-thumb {
      border-radius: 4px;
      background-color: rgba(144, 147, 153, 0.3);
    }
    
    li {
      list-style: none;
      padding: 8px 16px;
      position: relative;
      cursor: pointer;
      
      &:hover {
        background: $select-draggable-color;
      }

      p {
        margin: 0 !important;
      }
      
      .checked {
        display: none;
        position: absolute;
        right: 5px;
        top: calc(50% - 4px);
        width: 10px;
        height: 5px;
        border-left: 1px solid $color-primary;
        border-bottom: 1px solid $color-primary;
        transform: rotateZ(-45deg);
      }
    }
    li:last-child {
      &:hover {
        background: white;
      }
    }
    
    li.selected {
      // background-color: $select-draggable-color;
      color: $color-primary;
      background-color: #E7F9F9;
      p > span {
        color: $color-primary;
      }
      /*font-weight: 700;*/
      
      .checked {
        display: block;
      }
    }
    
    .list-message {
      color: $text-color-secondary;
    }
  }
}

.list-wrapper[x-placement="bottom-start"] {
  .arrow-bottom {
    top: -7px;
    transform: rotateZ(0deg);
  }
  .input-container {
    position: absolute;
    top: 0;
  }
  .option-list {
    position: absolute;
    top: 40px;
  }
}

.option-list {
  .customer-template-option {
    & > p {
      display: flex;
      flex-flow: column;
    }
  }
}

.inputAlwayTop[x-placement="top-start"] {
  display: flex;
  flex-direction: column;
  .option-list {
    order: 1;
  }
}
</style>